using SharpDX;
using SharpDX.Direct3D11;
using System.Collections;
using System.IO;
using System.Runtime.InteropServices;

namespace Engine.Graphics.VertexStructures
{
    public class MyOwnVertex
    {
        #region Public Structs

        [StructLayout(LayoutKind.Sequential)]
        public struct MyPositionNormalTextured : IEnumerable, ICollection //: IComparable<MyPositionNormalTextured>
        {
            //public Vector3 Position;
            //public Color4 vertexColor;
            //Color4 diffuseColor;
            //public Vector3 Normal;
            //public Vector2 UV;
            //public Vector3 Tangent;
            //public Vector3 BiNormal;
            //public Vector2 UV2;

            /// <summary>
            /// Create the Vertex Element Array
            /// </summary>
            public static InputElement[] elements = new InputElement[]{
                new InputElement("POSITION", 0, SharpDX.DXGI.Format.R32G32B32_Float,0,0, InputClassification.PerVertexData, 0),//Position
                new InputElement("COLOR", 0, SharpDX.DXGI.Format.R32G32B32A32_Float,12,0, InputClassification.PerVertexData, 0),// Diffuse Color
                new InputElement("COLOR", 1, SharpDX.DXGI.Format.R32G32B32A32_Float,28,0, InputClassification.PerVertexData, 0), // VertexColor
                new InputElement("NORMAL", 0, SharpDX.DXGI.Format.R32G32B32_Float,44,0, InputClassification.PerVertexData, 0), // Normal
                new InputElement("TEXCOORD", 0, SharpDX.DXGI.Format.R32G32_Float,56,0, InputClassification.PerVertexData, 0),// UV1
                new InputElement("TEXCOORD", 1, SharpDX.DXGI.Format.R32G32_Float,64,0, InputClassification.PerVertexData, 0),//UV2

                //new InputElement(0, 28, DeclarationType.Float4,
                //                         DeclarationMethod.Default,
                //                         DeclarationUsage.Color, 1),

                //new InputElement(0, 44, DeclarationType.Float3,
                //                         DeclarationMethod.Default,
                //                         DeclarationUsage.Normal, 0),

                //new InputElement(0, 56, DeclarationType.Float2,
                //                         DeclarationMethod.Default,
                //                         DeclarationUsage.TextureCoordinate, 0),

                //new InputElement(0, 64, DeclarationType.Float2,
                //                         DeclarationMethod.Default,
                //                         DeclarationUsage.TextureCoordinate, 1),
            };

            //public static readonly VertexFormat Format = VertexFormat.Position | VertexFormat.Diffuse | VertexFormat.Texture3 | VertexFormat.Normal;
            public Color4 DiffuseColor
            {
                get { return diffuseColor; }
                set { diffuseColor = value; }
            }

            public float Nx
            {
                get { return this.Normal.X; }
                set { this.Normal.X = value; }
            }

            public float Ny
            {
                get { return this.Normal.Y; }
                set { this.Normal.Y = value; }
            }

            public float Nz
            {
                get { return this.Normal.Z; }
                set { this.Normal.Z = value; }
            }

            public float Tu
            {
                get { return this.UV.X; }
                set { this.UV.X = value; }
            }

            public float Tv
            {
                get { return this.UV.Y; }
                set { this.UV.Y = value; }
            }

            public float Tu2
            {
                get { return this.UV2.X; }
                set { this.UV2.X = value; }
            }

            public float Tv2
            {
                get { return this.UV2.Y; }
                set { this.UV2.Y = value; }
            }

            public Color4 VertexColor
            {
                get { return this.vertexColor; }
                set { this.vertexColor = value; }
            }

            public float X
            {
                get { return this.Position.X; }
                set { this.Position.X = value; }
            }

            public float Y
            {
                get { return this.Position.Y; }
                set { this.Position.Y = value; }
            }

            public float Z
            {
                get { return this.Position.Z; }
                set { this.Position.Z = value; }
            }

            public static bool operator !=(MyPositionNormalTextured a, MyPositionNormalTextured b)
            {
                //if (a.GetHashCode() != b.GetHashCode())
                //    return true;
                //return false;
                if (a.Position == b.Position &&
                    a.Normal == b.Normal &&
                    a.UV.Equals(b.UV) &&
                    a.vertexColor.Equals(b.vertexColor) &&
                    a.diffuseColor.Equals(b.diffuseColor))
                    return false;

                return true;
            }

            public static bool operator ==(MyPositionNormalTextured a, MyPositionNormalTextured b)
            {
                //if (a.GetHashCode() != b.GetHashCode())
                //    return false;
                //return true;
                if (a.Position != b.Position)
                    return false;
                if (a.Normal != b.Normal)
                    return false;
                if (a.UV != b.UV)
                    return false;
                if (a.vertexColor != b.vertexColor)
                    return false;
                //MyPositionNormalTextured.doubleVerticesFound++;
                return true;
            }

            public static MyPositionNormalTextured FromStream(BinaryReader br)
            {
                MyPositionNormalTextured vertex = new MyPositionNormalTextured();

                vertex.Position.X = br.ReadSingle();
                vertex.Position.Y = br.ReadSingle();
                vertex.Position.Z = br.ReadSingle();

                vertex.Normal.X = br.ReadSingle();
                vertex.Normal.Y = br.ReadSingle();
                vertex.Normal.Z = br.ReadSingle();

                vertex.UV.X = br.ReadSingle();
                vertex.UV.Y = br.ReadSingle();
                //vertex.UV.Z = br.ReadSingle();
                //vertex.UV.W = br.ReadSingle();
                br.BaseStream.Position += 8;

                vertex.diffuseColor = new Color4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
                vertex.vertexColor = new Color4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle());

                return vertex;
            }

            private void UpdateBinormalTangent()
            {
            }

            public MyPositionNormalTextured(Vector3 position, Vector3 normal, float Tu, float Tv, float Tu2, float Tv2, Color4 vertexColor)
            {
                this.Position = position;
                this.UV = new Vector2(Tu, Tv);//, 0.0f, 0.0f);
                this.UV2 = new Vector2(Tu2, Tv2);

                // defuse Color: XXX, R, G, B
                this.diffuseColor = new Color4(1.0f, 0.4f, 0.4f, 0.4f);

                // Vertex color for blending. alpha is for shadow
                this.vertexColor = vertexColor;

                this.Normal = normal;
            }

            public MyPositionNormalTextured(Vector3 position, Vector3 normal, float Tu, float Tv, float Tu2, float Tv2, Color4 diffuseColor, Color4 blendColor)
                : this(position, normal, Tu, Tv, Tu2, Tv2, blendColor)
            {
                this.diffuseColor = diffuseColor;
            }

            public void SaveToStream(BinaryWriter bw)
            {
                // Rite Position;
                bw.Write(this.Position.X);
                bw.Write(this.Position.Y);
                bw.Write(this.Position.Z);
                // Write Normal;
                bw.Write(this.Normal.X);
                bw.Write(this.Normal.Y);
                bw.Write(this.Normal.Z);
                // Write UV;
                bw.Write(this.UV.X);
                bw.Write(this.UV.Y);

                bw.Write(this.UV.X);
                bw.Write(this.UV.Y);

                //bw.Write(this.UV.Z);
                //bw.Write(this.UV.W);

                // Write diffuseColr;
                bw.Write(this.diffuseColor.Alpha);
                bw.Write(this.diffuseColor.Red);
                bw.Write(this.diffuseColor.Green);
                bw.Write(this.diffuseColor.Blue);
                // Write vertexColor;
                bw.Write(this.vertexColor.Alpha);
                bw.Write(this.vertexColor.Red);
                bw.Write(this.vertexColor.Green);
                bw.Write(this.vertexColor.Blue);
            }

            public void SetNormal(Vector3 normal)
            {
                this.Normal = normal;
            }

            public static int SizeInBytes()
            {
                return Marshal.SizeOf(typeof(MyPositionNormalTextured));
            }

            public override string ToString()
            {
                return ("Pos: " + this.Position.ToString() + " normal: " + this.Normal.ToString() + " UV: " + this.UV.ToString());
            }

            #region VertexData (Do not remove this region!!)

            // 0
            public Vector3 Position;

            // 0 + 12 = 12
            private Color4 diffuseColor;

            // 12 + 16 = 28
            public Color4 vertexColor;

            // 28 + 16 = 44
            public Vector3 Normal;

            // 44 + 12 = 56
            public Vector2 UV;

            // 56 + 8 = 64
            public Vector2 UV2;

            #endregion VertexData (Do not remove this region!!)

            public IEnumerator GetEnumerator()
            {
                throw new System.NotImplementedException();
            }

            public void CopyTo(System.Array array, int index)
            {
                throw new System.NotImplementedException();
            }

            public int Count
            {
                get { throw new System.NotImplementedException(); }
            }

            public bool IsSynchronized
            {
                get { throw new System.NotImplementedException(); }
            }

            public object SyncRoot
            {
                get { throw new System.NotImplementedException(); }
            }
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct PositionNormalTextured : IEnumerable //: IComparable<MyPositionNormalTextured>
        {
            //public static readonly VertexFormat Format = VertexFormat.Position | VertexFormat.Texture1 | VertexFormat.Normal;

            #region VertexData (Do not remove this region!!)

            public Vector3 Position;
            public Vector3 Normal;
            public Vector2 UV;

            #endregion VertexData (Do not remove this region!!)

            public IEnumerator GetEnumerator()
            {
                throw new System.NotImplementedException();
            }
        }

        #endregion Public Structs
    }
}